#include "Discover.h"
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/msg.h>
#include "QClientInit.h"
#include "../QCommon/QCommon.h"
#include <iostream>

using namespace std;
void* check_online(void *arg)
{
    Discover *discover=(Discover*)arg;
    while(true)
    {
        sleep(REFRESH_INTERVAL);
        int i=discover->flags->size();
        while(--i>=0)
        {
            vector<bool> &f=*(discover->flags);
            f[i]=false;
        }
    }
    return NULL;
}

Discover::Discover()
{
    this->users=new vector<User>;
    this->flags=new vector<bool>;
    pthread_t tid;
    pthread_create(&tid,NULL,check_online,this);
}

Discover::~Discover()
{
    delete this->users;
    delete this->flags;
}

void Discover::setOffline(User &user)
{
    int size=users->size();
    vector<User> &u=*users;
    vector<bool> &f=*flags;
    while(--size>=0)
    {
        User &tu=u[size];
        if(tu.ip==user.ip && tu.name==user.name && tu.pid==user.pid)
        {
            f[size]=false;
            break;
        }
    }
}

void Discover::setOnline(User &user)
{
    int size=users->size();
    vector<User> &u=*users;
    vector<bool> &f=*flags;
    while(--size >= 0)
    {
        User &tu=u[size];
        if(tu.ip==user.ip && tu.name==user.name && tu.pid==user.pid)
        {
            f[size]=true;
            break;
        }
    }
    if(size<0)
    {
        u.push_back(user);
        f.push_back(true);
    }
}

vector<User> Discover::getOnlineUsers()
{
    int size=users->size();
    vector<User> &u=*users;
    vector<bool> &f=*flags;
    vector<User> result;
    while(--size>=0)
    {
        if(f[size])
        {
            result.push_back(u[size]);
        }
    }
    return result;
}



void* broadcast(void *arg)
{
    Notify *notify=(Notify*)arg;
    while(true)
    {
        sleep(NOTIFY_INTERVAL);
        if(notify->user->status == online)
        {
            NetworkEvent e;
            strcpy(e.dest_ip,notify->address->broadcast_addr);
            strcpy(e.src_ip,notify->address->ip_addr);
            strcpy(e.name,notify->user->name.c_str());
            e.gender=notify->user->gender;
            e.status=notify->user->status;
            msgsnd(retrieve_msqid(),&e,size_event(e)-sizeof(long),0);
        }
    }
    return NULL;
}

Notify::Notify()
{
    address=new Address;
    struct ifreq ifr;
    int inet_sock;
    strcpy(ifr.ifr_name, "eth0");
    ifr.ifr_addr.sa_family=AF_INET;
    inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
    ioctl(inet_sock, SIOCGIFADDR, &ifr);
    struct sockaddr_in *addr=(struct sockaddr_in*)&ifr.ifr_addr;
    strcpy(address->ip_addr,inet_ntoa(addr->sin_addr));

    ioctl(inet_sock, SIOCGIFBRDADDR,&ifr);
    addr=(struct sockaddr_in*)&ifr.ifr_addr;
    strcpy(address->broadcast_addr,inet_ntoa(addr->sin_addr));
}

Notify::~Notify()
{
    delete user;
}

void Notify::setUser(User &u)
{
    user=&u;
    u.ip=(string)address->ip_addr;
    pthread_t tid;
    pthread_create(&tid,NULL,broadcast,this);
}

const User& Notify::getUser() const
{
    return *user;
}

int Discover::search_user_index(string ip, int pid)
{
	vector<User> _users = *users;
	for(int i = 0; i < _users.size(); i++){
		if(_users[i].ip == ip && _users[i].pid == pid)
			return i;
	}
	return -1;
}

User Discover::search_user(int index)
{
	vector<User> _users = *users;
	if(index>=users->size() || index<0)
		return _users[_users.size()-1];
    return _users[index];
	
}
